﻿using Awsc.DataAcquisitionSys.Core.DataAcquisition;
using Awsc.DataAcquisitionSys.Core.Messages;
using Awsc.DataAcquisitionSys.Core.Model.Config;
using Awsc.DataAcquisitionSys.Core.Models.POCO;
using Awsc.DataAcquisitionSys.Core.Repository;
using MediatR;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Data;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Awsc.DataAcquisitionSys.Core.Databases
{
    public class MissionDataWriter : IDisposable
    {
        private const int BatchSize = 500;       // 每批处理的数据点数量
        private const int CommitIntervalMs = 50; // 最大提交间隔(ms)

        private bool _isRecording = true;
        private bool _disposed;
        private Mission _currentMission;
        private List<SensorConfig> _currentSensorList = new List<SensorConfig>();
        private SqliteConnection _connection;
        private string _insertSql;
        private Thread _writerThread;
        private readonly object _schemaLock = new();
        private readonly SQLiteHelper sQLiteHelper;
        private DeviceConfig _deviceConfig;
        private PeriodicTimer _timer = new PeriodicTimer(TimeSpan.FromMilliseconds(200));


        public MissionDataWriter(IOptionsMonitor<DeviceConfig> optionsMonitor, SQLiteHelper sQLiteHelper)
        {
            var connectionString = @$"Data Source=Missions\MissionProfile.db;";
            _connection = new SqliteConnection(connectionString);
            _connection.Open();
            this._deviceConfig = optionsMonitor.CurrentValue;
            optionsMonitor.OnChange((newConfig, name) =>
            {
                _deviceConfig = newConfig;
            });
            this.sQLiteHelper = sQLiteHelper;
            this._currentSensorList = _deviceConfig.GetAllSensorConfig();
        }


        public void StartRecording(Mission mission)
        {
            if(_isRecording)
            {
                StopRecording();
            }
            _disposed = false;
            this._currentMission = mission;
            this._currentSensorList = _deviceConfig.GetAllSensorConfig();
            CreateTableIfNotExist(mission);
            PrepareInsertCommand();


            // 启动高性能写入线程
            _writerThread = new Thread(async () => await WriteProcessingLoop())
            {
                Priority = ThreadPriority.Highest,
                IsBackground = true
            };
            _writerThread.Start();
            _isRecording = true;
        }

        private void CreateTableIfNotExist(Mission mission)
        {
            List<string> fields = new List<string>();
            foreach (var sensor in _currentSensorList)
            {
                if(sensor.IsCoil)
                {
                    fields.Add($"`{sensor.Name}` TEXT");
                }
                else
                {
                    fields.Add($"`{sensor.Name}` REAL");
                }

            }

            var columnsDefinition = string.Join(",\n", fields); 

            var sql = $@"CREATE TABLE IF NOT EXISTS `{mission.SensorDataTableName}` (
                        `Id` INTEGER PRIMARY KEY AUTOINCREMENT,
                        `MissionId` INTEGER,
                        `时间` REAL,
                        {columnsDefinition}
                    );
                    PRAGMA journal_mode = WAL;
                    PRAGMA synchronous = NORMAL;
                    PRAGMA cache_size = -10000;";

            sQLiteHelper.ExecuteNonQueryAsync(sql).ConfigureAwait(false).GetAwaiter().GetResult();

        }

        public void PauseRecording()
        {
            if (_currentMission != null)
            {
                _isRecording = false;
            }
        }
        public void ResumeRecording()
        {
            if (_currentMission != null)
            {
                _isRecording = true;
            }
        }
        public void StopRecording()
        {
            if(_isRecording)
            {
                _isRecording = false;
                Dispose();
            }

        }
        public void AddSensor(SensorConfig config)
        {
            if (_isRecording)
            {
                PauseRecording();
            }

            lock (_schemaLock)
            {
                if (_currentSensorList.Any(s => s.Name == config.Name))
                {
                    Console.WriteLine($"传感器 {config.Name} 已存在，无法添加。");
                    return;
                }
                var dataType = config.IsCoil ? "TEXT" : "Real";
                var sql = $"ALTER TABLE `{_currentMission.SensorDataTableName}` ADD COLUMN `{config.Name}` {dataType}";
                var execResult = sQLiteHelper.ExecuteNonQuery(sql);
             
                if (execResult > 0)
                {
                    _currentSensorList.Add(config);
                    PrepareInsertCommand();
                }
                ResumeRecording();

            }
        }

        public void RemoveSensor(SensorConfig config)
        {
            if (_isRecording)
            {
                PauseRecording();
            }

            lock (_schemaLock)
            {
                _currentSensorList.RemoveAll(c=>c.Name==config.Name);
                PrepareInsertCommand();
                ResumeRecording();
            }
        }

        public void Dispose()
        {
            if (_disposed) return;

            _disposed = true;

            // 等待写入线程结束（最多2秒）
            if (_writerThread != null && _writerThread.IsAlive)
            {
                _writerThread.Join(2000);
            }
            // 优化关闭前的数据库整理
            if (_connection != null && _connection.State == ConnectionState.Open)
            {
                using var cmd = new SqliteCommand("PRAGMA optimize", _connection);
                cmd.ExecuteNonQuery();
                _connection.Close();
            }
            _connection?.Dispose();
            _currentMission = null;
            _currentSensorList = null;
            GC.SuppressFinalize(this);
        }

        private void PrepareInsertCommand()
        {
            lock (_schemaLock)
            {
                var columns = string.Join(", ", _currentSensorList.Select(s => $"`{s.Name}`"));
                var parameters = string.Join(", ", _currentSensorList.Select(s => $"@[{s.Name}]"));
                _insertSql = $"INSERT INTO `{_currentMission.SensorDataTableName}` (MissionId, 时间, {columns}) " +
                    $"VALUES ({_currentMission.Id}, @[Timestamp], {parameters})";
            }
        }


        private async Task WriteProcessingLoop()
        {
            var batch = new List<SensorDataRow>(BatchSize);
            var lastCommitTime = DateTime.UtcNow;


            while (_isRecording && !_disposed)
            {
                try
                {
                    await _timer.WaitForNextTickAsync();

                    var sql = _insertSql;
                    var sw = Stopwatch.StartNew();
                    int pointsProcessed = 0;



                    if (_currentMission != null)
                    {
                        var allSensor = GlobalDeviceManager.Instance.GetAllSensors();
                        foreach (var sensor in allSensor)
                        {
                            if (sensor.CurrentValue == null)
                            {
                                sql = sql.Replace($"@[{sensor.Name}]", "NULL");
                            }
                            else
                            {
                                if (sensor.IsAIRegister || sensor.IsAORegister)
                                {
                                    sql = sql.Replace($"@[{sensor.Name}]", $"{sensor.CurrentValue}");
                                }
                                else
                                {
                                    sql = sql.Replace($"@[{sensor.Name}]", $"'{sensor.CurrentValue}'");
                                }
                            }



                        }

                        sql = sql.Replace("@[Timestamp]", DateTime.UtcNow.ToOADate().ToString());
                        await sQLiteHelper.ExecuteNonQueryAsync(sql);
                    }

                    sw.Stop();
                    Console.WriteLine($"写入 {pointsProcessed} 个数据点，耗时 {sw.ElapsedMilliseconds}ms");

                    batch.Clear();
                    lastCommitTime = DateTime.UtcNow;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"写入错误: {ex.Message}");
                    Thread.Sleep(100);
                }
            }
        }


    }
}
